package net.blogways.ordermgr.common.command.dbservice;

import com.asiainfo.bpc.utils.ToolFactory;
import com.asiainfo.utils.Utils;
import net.blogways.ordermgr.entity.KeyGenerator;
import net.blogways.ordermgr.util.Constants;
import net.blogways.ordermgr.util.DBTools;
import net.blogways.ordermgr.util.RescodeConstants;
import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * @author chenlong
 * Created on 2018/7/24
 */
@Component("common:syncOperate")
public class SyncOperateCommand implements Command {

  private final Logger log = LoggerFactory.getLogger(getClass());

  @Override
  public boolean execute(Context context) throws Exception {
    return Command.CONTINUE_PROCESSING;
  }

  public boolean operate(Context context) throws Exception {

    if (sql_inj(context.toString())) {
      return Utils.returnFalseResult(context, RescodeConstants.ILLEGAL_CHARACTER, "非法参数");
    }


    long retCnt = 0L;

    if (!context.containsKey("Base")) {
      return Utils.returnFalseResult(context, "0001", "common_miss_base");
    }



    Map<String, Object> base = (Map<String, Object>) context.get("Base");
    Map<String, Object> json = (Map<String, Object>) context.get("JSON");

    String operateCode = base.get("OPERATE_CODE") == null ? null : base.get("OPERATE_CODE").toString();

    String dbRoute;

    if (context.get("dbRoute") != null) {
      dbRoute = (String) context.get("dbRoute");
    } else {
      dbRoute = Constants.DATABASE_CEN;
    }
    if (json.get("TF_F_ORDER") != null && json.get("openId") != null){
      if (dbRoute.equals(Constants.DATABASE_CEN)){
        if (base.get("dbRoute") != null) {
          dbRoute = (String) base.get("dbRoute");
        } else {
          dbRoute = Constants.DATABASE_CEN;
        }
      }
    }


    String sucCode = base.containsKey("I18N_KEY_SUC") ? base.get("I18N_KEY_SUC").toString() : "common_operate_ok";
    String failCode = base.containsKey("I18N_KEY_FAIL") ? base.get("I18N_KEY_FAIL").toString() : null;
    KeyGenerator generator = null;
    if (base.get("ID_RULE") != null && !StringUtils.isEmpty(base.get("ID_RULE").toString())) {
      generator = new KeyGenerator(base.get("ID_RULE").toString());
      base.put("pks", generator);
    }

    for (String tblStr : json.keySet()) {

      if (!(json.get(tblStr) instanceof List)) {
        if (base.get("IN_MODE_CODE") != null && "1".equals(base.get("IN_MODE_CODE").toString())) {
          continue;
        }
        log.debug("enter not list error, key: {}, value: {}", tblStr, json.get(tblStr).toString());
        return Utils.returnFalseResult(context, "0001", "common_tab_key_arr");
      }

      List<Map<String, Object>> tuples = (List<Map<String, Object>>) json.get(tblStr);

      for (Map<String, Object> tuple : tuples) {
        String modifyTag = tuple.get("MODIFY_TAG").toString();

        switch (modifyTag) {
          case "0":
            if (generator != null) {
              Map<String, Object> keys = generator.getKeys(tuple);
              base.put("PKS", keys);
              tuple.putAll(keys);
            }
            try {
              retCnt += this.insertOperate(tblStr, tuple, dbRoute);
            } catch (Exception e) {
              String exceptionCode = failCode == null ? "操作失败，请重试" : failCode;
              log.error("Sync Insert Operate Failed, Cause: {}", e.getMessage());
              return Utils.returnFalseResult(context, "0001", exceptionCode);
            }
            break;

          case "1":
            try {
              retCnt += this.deleteOperate(tblStr, tuple, dbRoute);
            } catch (Exception e) {
              String exceptionCode = failCode == null ? "操作失败，请重试" : failCode;
              log.error("Sync Delete Operate Failed, Cause: {}", e.getMessage());
              return Utils.returnFalseResult(context, "0001", exceptionCode);
            }
            break;

          case "2":
            try {
              retCnt += this.updateOperate(tblStr, tuple, dbRoute);
            } catch (Exception e) {
              String exceptionCode = failCode == null ? "操作失败，请重试" : failCode;
              log.error("Sync Update Operate Failed, Cause: {}", e.getMessage());
              return Utils.returnFalseResult(context, "0001", exceptionCode);
            }
            break;
        }
      }
      if (generator != null) {
        generator.resetCounter();
      }
    }
    if (retCnt == 0) {
      return Utils.returnFalseResult(context, "0001", failCode);
    }
    DBTools.checkBeforeEnd(context);
    return Utils.returnOkResult(context, "操作成功");
  }

  private long insertOperate(String tblStr, Map<String, Object> tuple, String dbRoute) throws Exception {
    long cnt = 0L;

    Map<String, Object> instParams = new HashMap<>();

    for (String col : tuple.keySet()) {
      instParams.put("V" + col, tuple.get(col));
    }

    log.debug("************************************************************************");
    log.debug("Sync Insert Operate Begin !");
    log.debug("SQL_REF: " + Constants.SQL_REF_COMMON.get(0));
    log.debug("TAB_NAME: " + tblStr);
    log.debug("PARAMS: " + instParams);
    log.debug("************************************************************************");
    cnt += ToolFactory.getInstance()
            .getSqlCodeService(dbRoute).insert(Constants.SQL_REF_COMMON.get(0), tblStr, instParams);

    return cnt;
  }

  private long updateOperate(String tblStr, Map<String, Object> tuple, String dbRoute) throws Exception {
    long cnt = 0L;

    Map<String, Object> updParams = new HashMap<>();
    String sql = "UPDATE " + tblStr + " SET ";
    String docs = "";
    String condition = " WHERE ";
    List<String> tmp = new ArrayList<String>();
    for (String col : tuple.keySet()) {

      if (tmp.contains(col)){
        continue;
      }
      if (col.contains("PK_") && tuple.get(col.substring(3)) != null){
        updParams.put("V" + col.substring(3) + "_BAK", tuple.get(col.substring(3)));
        docs += col.substring(3) + "=:V" + col.substring(3) + "_BAK" + ",";
        tmp.add(col.substring(3));
      }

      if (col.contains("PK_")) {
        String pk = col.replace("PK_", "");
        updParams.put("V" + pk, tuple.get(col));
        condition += pk + "=:V" + pk + " AND ";
      } else {
        if (!"MODIFY_TAG".equals(col)) {
          updParams.put("V" + col, tuple.get(col));
          docs += col + "=:V" + col + ",";
        }
      }
    }
    sql = sql +
            (docs.substring(0, docs.length() - 1)) + " " +
            (condition.substring(0, condition.length() - 4)) + ";";

    log.debug("************************************************************************");
    log.debug("Sync Update Operate Begin !");
    log.debug("Sql : : " + sql);
    log.debug("TAB_NAME: " + tblStr);
    log.debug("PARAMS: " + updParams);
    log.debug("************************************************************************");
    cnt += ToolFactory.getInstance().getSqlCodeService(dbRoute).update(sql, updParams);

    return cnt;
  }

  private long deleteOperate(String tblStr, Map<String, Object> tuple, String dbRoute) throws Exception {
    long cnt = 0L;

    Map<String, Object> delParams = new HashMap<>();

    for (String col : tuple.keySet()) {
      if (col.contains("PK_")) {
        if(col.contains("PK_USER_NAME")){
          delParams.put("VPK_USER_NAME", tuple.get(col));
        }
        delParams.put("V" + col.replace("PK_", ""), tuple.get(col));
      } else {
        delParams.put("V" + col, tuple.get(col));
      }
    }

    log.debug("************************************************************************");
    log.debug("Sync Delete Operate Begin !");
    log.debug("SQL_REF : : " + Constants.SQL_REF_COMMON.get(1));
    log.debug("TAB_NAME: " + tblStr);
    log.debug("PARAMS: " + delParams);
    log.debug("************************************************************************");
    cnt += ToolFactory.getInstance().getSqlCodeService(dbRoute).update(Constants.SQL_REF_COMMON.get(1), tblStr, delParams);

    return cnt;
  }

  public static boolean sql_inj(String str){

    String[] inj_str = {".*\\$(?!\\{.+?\\}).*",};

    int len = inj_str.length;
    for (int i = 0; i < len; i++) {
      String reg = inj_str[i];
      if (str.matches(reg)) {
        return true;
      }
    }
    return false;

  }
}
